package vip.youngboy.freejump.handler.task;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandExecutor;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import vip.youngboy.freejump.domain.FileInfo;
import vip.youngboy.freejump.domain.FlowRequestParam;
import vip.youngboy.freejump.domain.TaskActionModel;
import vip.youngboy.freejump.domain.process.TaskOpinion;
import vip.youngboy.freejump.parse.user.UserSettingParser;
import vip.youngboy.freejump.persist.bus.busdata.BusDataPersistence;
import vip.youngboy.freejump.persist.file.FilePersistence;
import vip.youngboy.freejump.repository.TaskOpinionRepository;
import vip.youngboy.freejump.service.user.UserService;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public abstract class AbstractTaskActionHandler implements TaskActionHandler {

    @Autowired
    protected FilePersistence filePersistence;

    @Autowired
    protected TaskOpinionRepository taskOpinionRepository;

    @Autowired
    protected IdentityService identityService;

    @Autowired
    protected TaskService taskService;

    @Autowired
    protected UserSettingParser userSettingParser;

    @Autowired
    protected ProcessEngineConfiguration processEngineConfiguration;
    @Autowired
    protected BusDataPersistence busDataPersistence;
    @Autowired
    private UserService userService;

    @Transactional
    @Override
    public void handleAction(FlowRequestParam flowRequestParam) {
        // 处理 flowRequestParam 中的一些业务数据和用户设置数据 校验options
        vaildOptions(flowRequestParam);
        String taskId = flowRequestParam.getTaskId();
        String assignUser = getAssignUser();
        Task currentTask = findTaskById(taskId);
        Assert.notNull(currentTask, "找不到对应的task");
        TaskActionModel taskActionModel = new TaskActionModel();
        taskActionModel.setFlowRequestParam(flowRequestParam);
        taskActionModel.setTask(currentTask);
        taskActionModel.setAssign(assignUser);
        //校验用户是否合法
        vaildUser(taskActionModel);
        //保存流转记录
        recordTaskOption(taskActionModel);
        //设置当前处理人
        identityService.setAuthenticatedUserId(assignUser);
        persistBusData(currentTask.getProcessDefinitionId(), flowRequestParam.getData());
        //交给子类完成剩余逻辑
        doHandleAction(taskActionModel);
    }


    /**
     * 持久化业务数据
     *
     * @param procDefId 流程定义id
     * @param busData   业务数据
     * @return 业务id
     */
    public String persistBusData(String procDefId, JSONObject busData) {
        if (busData == null) {
            return null;
        }
        return busDataPersistence.persistBusData(procDefId, busData);
    }


    /**
     * 记录处理动作和处理人评论附件信息
     *
     * @param taskActionModel 任务处理模型
     */
    protected void recordTaskOption(TaskActionModel taskActionModel) {
        FlowRequestParam flowRequestParam = taskActionModel.getFlowRequestParam();
        List<FileInfo> files = flowRequestParam.getFiles();
        String taskId = flowRequestParam.getTaskId();
        //保存附件
        batchSaveFile(files, taskId);
        //记录处理动作和处理人评论
        recordTaskOpinion(taskActionModel);
    }

    protected Task findTaskById(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        return task;
    }

    /**
     * 记录任务结束流转记录
     *
     * @param taskActionModel 任务处理模型
     */
    protected void recordTaskOpinion(TaskActionModel taskActionModel) {
        Task task = taskActionModel.getTask();
        String taskId = task.getId();
        TaskOpinion startTaskOpinion = taskOpinionRepository.findFirstByTaskId(taskId);
        String assign = getAssignUser();
        TaskOpinion endTaskOpinion = TaskOpinion.createEndTaskOpinion(startTaskOpinion, taskActionModel, assign);
        taskOpinionRepository.save(endTaskOpinion);
    }

    /**
     * 校验用户是否可以处理此任务，即用户是否在候选人列表和是否为assign用户
     *
     * @param taskActionModel 任务处理模型
     */
    protected void vaildUser(TaskActionModel taskActionModel) {
        String assign = taskActionModel.getAssign();
        List<IdentityLink> identityLinksForTask = taskService.getIdentityLinksForTask(taskActionModel.getFlowRequestParam().getTaskId());
        if (!identityLinksForTask.contains(assign)) {
            throw new ActivitiException("您不在处理人列表中，不能处理此任务");
        }
    }

    /**
     * 完成剩下的动作
     *
     * @param taskActionModel 任务处理模型
     */
    public abstract void doHandleAction(TaskActionModel taskActionModel);

    /**
     * 校验options选项
     *
     * @param flowRequestParam 请求对象
     */
    public abstract void vaildOptions(FlowRequestParam flowRequestParam);

    /**
     * 获取当前的处理人
     *
     * @return
     */
    protected String getAssignUser() {
        return userService.getCurrentUserWithException().getId();
    }

    /**
     * 批量保存文件信息
     *
     * @param files 文件集合
     * @param outId 关联id
     */
    protected void batchSaveFile(List<FileInfo> files, String outId) {
        if (!CollectionUtils.isEmpty(files)) {
            List<FileInfo> fileInfos = files.stream().map(item -> {
                item.setOutId(outId);
                return item;
            }).collect(Collectors.toList());
            filePersistence.persistenceFileInfo(fileInfos);
        }
    }


    /**
     * 解析人员信息 支持选择人,角色，按组织选择
     * {
     * "name":"userchoose",
     * "result":[
     * {
     * "data":["1001","1002"],
     * "type":"user"
     * },
     * {
     * "data":["1001","1002"],
     * "type":"org"
     * },
     * {
     * "data":["1001","1002"],
     * "type":"role"
     * }
     * ]
     * }
     *
     * @param flowRequestParam 前端请求对象
     */
    protected Set<String> parseUserOptions(FlowRequestParam flowRequestParam) {
        return userSettingParser.parseUserOptions(flowRequestParam);
    }


    /**
     * 执行命令类
     *
     * @param command 命令类
     */
    protected void executeCommand(Command command) {
        CommandExecutor commandExecutor = ((SpringProcessEngineConfiguration) processEngineConfiguration).getCommandExecutor();
        commandExecutor.execute(command);
    }


}
